package cn.maihe.elg.operation.supports.bank.service;

import cn.maihe.elg.operation.config.ZtAccountInfo;
import cn.maihe.elg.operation.repository.entity.SpdBankNotice;
import cn.maihe.elg.operation.service.order.AcceptOrderInfoService;
import cn.maihe.elg.operation.service.order.SpdBankNoticeService;
import cn.maihe.elg.operation.supports.bank.BaseCcbBankTransService;
import cn.maihe.elg.operation.supports.bank.ccb.ebs.dto.CCBEbsTransDetailList;
import cn.maihe.elg.operation.supports.bank.ccb.ebs.dto.CCBEbsTransDetailQueryReq;
import cn.maihe.elg.operation.supports.bank.ccb.ebs.dto.CCBEbsTransDetailQueryResp;
import cn.maihe.elg.operation.supports.bank.ccb.ebs.dto.CCBEbsTransDetailXmlReq;
import cn.maihe.elg.operation.supports.bank.ccb.ebs.dto.CCBEbsTransDetailXmlResp;
import cn.maihe.elg.operation.supports.bank.enums.CcbMethod;
import cn.maihe.elg.operation.utils.DateUtil;
import cn.maihe.elg.operation.utils.ElgLogger;
import cn.maihe.elg.operation.utils.IdGenerate;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * @Description 建设银行查询账户流水
 * @Author Alan
 */
@Service
@Slf4j
public class CcbBankAccountDetailService extends BaseCcbBankTransService<CCBEbsTransDetailXmlReq, CCBEbsTransDetailXmlResp> {

    @Resource
    private SpdBankNoticeService spdBankNoticeService;
    @Resource
    private AcceptOrderInfoService acceptOrderInfoService;
    @Resource
    private ZtAccountInfo ztAccountInfo;

    private AtomicBoolean running = new AtomicBoolean(false);

    protected CcbMethod ccbMethod() {
        return CcbMethod.Q6WY105;
    }

    @Scheduled(cron = "${cn.maihe.elg.bank.ccb-bank.getAccountDetailCore}")
    public void scheduleBiSafeAccountDetail() {

        if (!"1".equals(ccbBankConfig.getOpenFlag())) {
            log.info("当前已关闭招商银行银企直连功能，暂无需开启定时拉取账户明细任务");
            return;
        }

        if (running.compareAndSet(false, true)) {
            long start = System.currentTimeMillis();
            ElgLogger.info(log, l -> l.info("定时拉取账户明细开始>>>"));
            try {
                //若是凌晨00:30前则需要同步昨天的记录，以防行内来账较迟
                LocalDateTime startDate = LocalDateTime.now().withHour(0).withMinute(0).withSecond(0);
                if (LocalTime.now().isBefore(LocalTime.of(0, 30, 0))) {
                    startDate = startDate.minusDays(1);
                }

                this.getAccountDetail(1, startDate, LocalDateTime.now());
            } catch (Exception e) {
                ElgLogger.error(log, l -> l.error("定时拉取账户明细异常:{}", e.getMessage(), e));
            } finally {
                running.set(false);
                long end = System.currentTimeMillis();
                ElgLogger.info(log, l -> l.info("定时拉取账户明细完成<<<耗时[" + (end - start) / 1000 + "S]"));
            }
        } else {
            ElgLogger.info(log, l -> l.info("定时拉取账户明细开始>>>已存在同步拉取任务，等待下一个定时任务重跑"));
        }
    }

    public boolean getAccountDetail(int startRow, LocalDateTime startDate, LocalDateTime endDate) {
        Integer mixRsltNum = 50;
        CCBEbsTransDetailQueryReq req = new CCBEbsTransDetailQueryReq(ccbBankConfig.getCustId(), ccbBankConfig.getUserId(),
                ccbBankConfig.getUserPwd(), ccbMethod().getMethodId(), ccbBankConfig.getAccNo(),
                startDate.format(DateTimeFormatter.ofPattern("yyyyMMdd")));
        req.setPage(startRow < 1 ? 1 : startRow);
        req.setTotalRecord(mixRsltNum);

//        XibAccountDetailReqDTO accountDetailReqDTO = new XibAccountDetailReqDTO();
//        //请求体body
//        XibAccountDetailReqBody accountDetailReqBody = new XibAccountDetailReqBody();
//        accountDetailReqBody.setCustAcct(xibBankConfig.getAcctNo());
//        accountDetailReqBody.setTransDir("1");
//        accountDetailReqBody.setTransTimeStart(startDate.format(DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN)));
//        accountDetailReqBody.setTransTimeEnd(endDate.format(DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN)));
//        accountDetailReqBody.setPageSize(mixRsltNum);
//        accountDetailReqBody.setPageNo(startRow < 1 ? 1 : startRow);
////        accountDetailReqBody.setQueryNumber(mixRsltNum);
////        accountDetailReqBody.setBeginNumber(startRow < 1 ? 1 : startRow);
//        accountDetailReqDTO.setClearBody(accountDetailReqBody);

//        ParentAccountDetailReqDTO reqDTO = new ParentAccountDetailReqDTO();
//        reqDTO.setAreaCode(spdBankConfig.getAreaCode());
//        reqDTO.setSettleAcctNo(spdBankConfig.getSettleAcctNo());
//        reqDTO.setStartDate(startDate.format(DateTimeFormatter.ofPattern("yyyyMMdd")));
//        reqDTO.setEndDate(endDate.format(DateTimeFormatter.ofPattern("yyyyMMdd")));
//        reqDTO.setStrtRslt(String.valueOf(startRow < 1 ? 1 : startRow));
//        reqDTO.setTtlRquestRsltNum(String.valueOf(mixRsltNum));

        try {
            CCBEbsTransDetailXmlResp respDTO = this.queryTrans(req);
            if (respDTO == null) {
                throw new RuntimeException("账户响应报文为空");
            }
            if (respDTO.getCcbEbsTransDetailQueryResp() != null && !respDTO.getCcbEbsTransDetailQueryResp().getDetails().isEmpty()) {
//                Integer totalCount = respDTO.getClearBody().getTotalCount();
                Integer currentRespNum = respDTO.getCcbEbsTransDetailQueryResp().getDetails().size();
                //单次查询返回的记录数=返回结果记录数，则可能后面还有记录所以需要再次查询
                if (currentRespNum.equals(mixRsltNum)) {
                    Integer nextStartRow = startRow + 1;
                    // 查询有限流，需要根据实际尽量触发限流，暂休眠1s
                    try {
                        TimeUnit.SECONDS.sleep(1);
                    } catch (InterruptedException e) {
                        ElgLogger.error(log, l -> l.error("查询有限流，需要根据实际尽量触发限流，暂休眠1s。异常:{}", e.getMessage(), e));
                    }
                    processAcctTranDtlInfo(respDTO.getCcbEbsTransDetailQueryResp());
                    return getAccountDetail(nextStartRow, startDate, endDate);
                } else {
                    processAcctTranDtlInfo(respDTO.getCcbEbsTransDetailQueryResp());
                    return true;
                }
            } else {
                throw new RuntimeException("账户响应报文状态码非成功[" + respDTO.getRequestSn() + ":" + respDTO.getReturnCode() + "," + respDTO.getReturnMsg() + "]");
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private void processAcctTranDtlInfo(CCBEbsTransDetailQueryResp resp) {
        resp.getDetails().stream()
//                .filter(o -> "1".equals(o.getTransDir()))
                .filter(o -> {
                    boolean exists = spdBankNoticeService.existsCoreSerNo(o.getTranFlow());
                    return !exists;
                }).map(o -> this.buildXibBankNotice(resp, o)).forEach(o -> {
                    try {
                        saveAndAutoAuditWaitPayConfirm(o);
                    } catch (Exception e) {
                        ElgLogger.error(log, l -> l.error(e.getMessage(), e));
                    }

                });

    }

    @Transactional(rollbackFor = Exception.class)
    public void saveAndAutoAuditWaitPayConfirm(SpdBankNotice spdBankNotice) {
        try {
            SpdBankNotice dbSpdBankNotice = spdBankNoticeService.saveOrUpdate(spdBankNotice);
            acceptOrderInfoService.autoAuditWaitPayConfirm(dbSpdBankNotice);
        } catch (Exception e) {
            throw new RuntimeException("拉取账户明细核查受理订单到账异常", e);
        }
    }

    /**
     * 核心流水号唯一：来账账号+交易金额+附言包含的标段编号的定位某笔受理订单号到账证明
     */
    public SpdBankNotice buildXibBankNotice(CCBEbsTransDetailQueryResp ccbEbsTransDetailQueryResp, CCBEbsTransDetailList accountDetail) {
        String transDate = DateUtil.formatDateStr(accountDetail.getTrandate(), DateUtil.FORMAT_DATETIME, DateUtil.FORMAT_TRADEDATE);
        String transTime = DateUtil.formatDateStr(accountDetail.getTrantime(), DateUtil.FORMAT_DATETIME, DateUtil.FORMAT_TRADETIME);
        SpdBankNotice spdBankNotice = new SpdBankNotice();
        spdBankNotice.setId(IdGenerate.getId());
        spdBankNotice.setNoticeDate(transDate);
        spdBankNotice.setNoticeTime(transTime);
        spdBankNotice.setNoticeType(ccbMethod().getMethodId());
        spdBankNotice.setNoticeSerNo(accountDetail.getTranFlow());
        spdBankNotice.setZoneCode("");
        spdBankNotice.setSecuNo("");
        spdBankNotice.setSecuName("");
        spdBankNotice.setMerchNo("");
        spdBankNotice.setMerchName("");
        spdBankNotice.setParentAcctNo(ccbEbsTransDetailQueryResp.getAccNo());
        spdBankNotice.setParentAcctName(ztAccountInfo.getAccName());
        spdBankNotice.setDepSerNo(accountDetail.getTranFlow());
        spdBankNotice.setCoreSerNo(accountDetail.getTranFlow());
        spdBankNotice.setCoreTransDate(transDate);
        spdBankNotice.setCoreTransTime(transTime);
        spdBankNotice.setTransDate(transDate);
        spdBankNotice.setTransTime(transTime);
        //这里存储对方账号类型
        spdBankNotice.setBusiType("");
        spdBankNotice.setTransAmt(accountDetail.getAmt());
        spdBankNotice.setAcctBankName("");
        spdBankNotice.setAcctBankNo("");
        spdBankNotice.setAcctName(accountDetail.getAccName1());
        spdBankNotice.setAcctNo(accountDetail.getAccno2());
        spdBankNotice.setAttach(accountDetail.getMessage());
        spdBankNotice.setRemark1(null);
        spdBankNotice.setRemark2(null);
        spdBankNotice.setRemark3(null);
        spdBankNotice.setGmtCreate(new Date());
        spdBankNotice.setGmtModified(new Date());

        return spdBankNotice;
    }

    /**
     * 账户类型 string(2)
     * 00-客户入金 ==>客户入金通知	A1007
     * 01-非客户入金 非客户入金通知	A1010
     * 02-不明入金 不明入金通知	A1008
     * 03-客户出金 客户出金通知	A1004
     * 04-非客户出金 非客户出金通知	A1003
     * 05-调拨入金 内部资金调拨通知	A3003
     * 06-调拨出金 内部资金调拨通知	A3003
     */
    private static String getNoticeTypeByBookAcctType(String bookAcctType) {
        switch (bookAcctType) {
            case "00":
                return "A1007";
            case "01":
                return "A1010";
            case "02":
                return "A1008";
            case "03":
                return "A1004";
            case "04":
                return "A1003";
            case "05":
                return "A3003";
            case "06":
                return "A3003";
            default:
                return null;
        }
    }
}
